package com.springboot.ww.config.dynamic;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
import com.springboot.ww.dto.TenantDbListDTO;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.BeanUtil;
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.util.*;

/**
 * 租户动态数据源提供者类.
 *
 * @author yangruibo
 */
@Slf4j
@Component
public class TenantDynamicDataSourceProvider extends AbstractDataSourceProvider implements SmartLifecycle {

    public static final String COMMON_DSP_KEY = "common_config";

    public static final String APP_CODE = "oms";
    /**
     * 所有数据源配置属性
     */
    private Map<String, DataSourceProperty> dataSourcePropertiesMap;

    private volatile boolean running = false;

    public TenantDynamicDataSourceProvider(Map<String, DataSourceProperty> dataSourcePropertiesMap) {
        this.dataSourcePropertiesMap = dataSourcePropertiesMap;
    }

    public DataSourceProperty getDataSourceProperty(String tenantId) {
        DataSourceProperty dsp = null;
        if (dataSourcePropertiesMap.containsKey(tenantId)) {
            dsp = dataSourcePropertiesMap.get(tenantId);
        } else if (dataSourcePropertiesMap.containsKey(COMMON_DSP_KEY)) {
            dsp = BeanUtil.clone(dataSourcePropertiesMap.get(COMMON_DSP_KEY));
        } else {
            dsp = new DataSourceProperty();
        }
        return dsp;
    }

    @Override
    public void start() {
        this.loadTenantDsInstance();
        this.running = true;
    }

    @Override
    public void stop() {
        this.running = false;
    }

    @Override
    public boolean isRunning() {
        return this.running;
    }

    /**
     * 加载租户DB实例配置.
     */
    private void loadTenantDsInstance() {
        String systemCode = "oms";
        String result = HttpRequest.get("http://opms-service.box-tools.com/client/tenant/db_config_list?appCode=" + systemCode).execute().body();
        TenantDbListDTO tenantDbDTO = JSONUtil.toBean(result, TenantDbListDTO.class);
        if (!CollectionUtils.isEmpty((Collection) tenantDbDTO.getData())) {
            tenantDbDTO.getData().stream().forEach((tenantDb) -> {
                DataSourceProperty tenantDataSourceProperty = getDataSourceProperty(tenantDb.getTenantId());
                DruidConfig druid = new DruidConfig();
                druid.setFilters("");
                tenantDataSourceProperty.setUrl(tenantDb.getDbUrl())
                        .setUsername(tenantDb.getUsername())
                        .setPassword(tenantDb.getPassword())
                        .setDruid(druid);
                dataSourcePropertiesMap.put(tenantDb.getTenantId(), tenantDataSourceProperty);
            });
        }
    }

    @Override
    public Map<String, DataSource> loadDataSources() {
        if (dataSourcePropertiesMap.containsKey(COMMON_DSP_KEY)) {
            synchronized (this) {
                final DataSourceProperty TEMP_COMMON_DP = dataSourcePropertiesMap.remove(COMMON_DSP_KEY);
                Map<String, DataSource> candidateDataSources = this.createDataSourceMap(dataSourcePropertiesMap);
                dataSourcePropertiesMap.putIfAbsent(COMMON_DSP_KEY, TEMP_COMMON_DP);
                return candidateDataSources;
            }
        }

        return createDataSourceMap(dataSourcePropertiesMap);
    }

    /**
     * 创建数据源实例.
     *
     * @param dataSourceProperty 数据源属性集
     * @return
     */
    public DataSource createDataSource(String ds, DataSourceProperty dataSourceProperty) {
        dataSourcePropertiesMap.putIfAbsent(ds, dataSourceProperty);

        Map<String, DataSourceProperty> innerDataSourcePropertyMap = new HashMap<>(8);
        innerDataSourcePropertyMap.put(ds, dataSourceProperty);
        Map<String, DataSource> dataSourceMap = createDataSourceMap(innerDataSourcePropertyMap);
        return dataSourceMap.get(ds);
    }
}
